#pragma once

#include <iostream>     //包含标准输入输出流库
#include <sys/types.h>  //包含一些基本数据类型定义
#include <sys/socket.h> //包含套接字接口
#include <netinet/in.h> //包含IP地址和端口号等网络地址的定义
#include <unistd.h>     //提供对POSIX操作系统API的访问，如close()
#include <string>       //包含字符串类
#include <cstring>      //包含字符串处理函数，如memset()

#include "nocopy.hpp"   //可能是自定义的头文件，用于禁止类的拷贝操作
#include "Log.hpp"      //自定义日志系统头文件
#include "InetAddr.hpp" //自定义网络地址处理类头文件

using namespace log_ns; // 使用log_ns命名空间，可能包含日志系统的相关功能

static const int gsockfd = -1;      // 全局变量，表示无效的套接字描述符
static const int glocalport = 8888; // 全局变量，定义默认本地端口号

enum
{
    SOCKET_ERROR = 1, // 套接字错误代码
    BIND_ERROR        // 绑定错误代码
};

// UdpServer user("192.1.1.1",8889);
// 一般服务器主要是用来进行网络数据读取和写入的，io的
// 服务器io逻辑 和 业务逻辑 解耦
class UdpServer : public nocopy // 继承自nocopy,可能用于禁止拷贝和赋值操作
{
public:
    UdpServer(int localport = glocalport) // 构造函数，默认使用全局变量glocalport作为本地端口号
        : _sockfd(gsockfd),               // 初始化成员变量_sockfd为无效套接字描述符
          _localport(localport),          // 初始化成员变量_localport为传入的本地端口号
          _isrunning(false)               // 初始化成员变量_isrunning为false, 表示服务器未运行
    {
    }

    void InitServer() // 定义一个函数InitServer，它不接受任何参数，也不返回任何值。
    {
        // 1.创建socket文件
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        // 调用全局命名空间中的socket函数来创建一个socket。
        // AF_INET指定使用IPv4协议，SOCK_DGRAM指定使用数据报（UDP）协议。返回值_sockfd是创建的socket的文件描述符。

        if (_sockfd < 0) // 检查socket创建是否失败（文件描述符小于0表示失败）。
        {
            LOG(FATAL, "socket error\n");
            // 如果失败，记录一个致命错误日志。

            exit(SOCKET_ERROR);
            // 退出程序，SOCKET_ERROR是一个预定义的错误码，用于表示socket创建失败。
        }

        LOG(DEBUG, "socket create sucess,_sockfd:%d\n", _sockfd);
        // 如果socket创建成功，记录一个调试日志，显示socket创建成功并打印出socket的文件描述符。

        // 2.bind
        struct sockaddr_in local;         // 定义一个sockaddr_in结构体变量local，用于存储本地地址信息。
        memset(&local, 0, sizeof(local)); // 使用memset函数将local变量的内存区域全部初始化为0。
        local.sin_family = AF_INET;       // 设置local的sin_family字段为AF_INET，表示使用IPv4协议。
        local.sin_port = htons(_localport);
        // 将calport（一个本地定义的端口号）转换为网络字节序，并赋值给local的sin_port字段。

      
        local.sin_addr.s_addr = INADDR_ANY; // 服务器端，进行任意IP地址绑定

        int n = ::bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
        // 调用全局命名空间中的bind函数，将之前创建的socket与本地地址信息local绑定。返回值n用于检查绑定是否成功。

        if (n < 0)// 检查绑定是否失败（返回值小于0表示失败）。
        {
            
            LOG(FATAL, "bind error\n");// 如果失败，记录一个致命错误日志。

            exit(BIND_ERROR);// 退出程序，BIND_ERROR是一个预定义的错误码，用于表示绑定失败。
        }
        LOG(DEBUG, "socket bind success\n");// 如果绑定成功，记录一个调试日志，显示socket绑定成功。
    }

    void Start() // 开始服务器运行
    {
        _isrunning = true;   // 设置服务器运行状态为true
        char inbuffer[1024]; // 接收数据的缓冲区
        while (_isrunning)   // 循环运行直到_isrunning为false
        {
            struct sockaddr_in peer;
            //表示对端地_lo址
            socklen_t len = sizeof(peer);                                                                     // 对端地址长度
            ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr *)&peer, &len); // 接收数据
            if (n > 0)                                                                                        // 省略数据处理和发送回显代码...
            {
                InetAddr addr(peer);
                inbuffer[n] = 0;
                std::cout << "[" << addr.Ip() << ":" << addr.Port() << "]#" << inbuffer << std::endl;

                std::string echo_string = "[udp_sever echo] #";
                echo_string += inbuffer;
                sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (struct sockaddr *)&peer, len);
            }
            else
            {
                std::cout << "recvfrom,error" << std::endl;
            }
        }
    }
    ~UdpServer() // 析构函数
    {
        if (_sockfd > gsockfd) // 如果_sockfd是有效的套接字描述符
            ::close(_sockfd);  // 关闭套接字
    }

private:
    int _sockfd;    // 套接字描述符
    int _localport; // 本地端口号
    // stds::string _localip; //TODO:后面专门要处理一下这个IP
    bool _isrunning; // 服务器运行状态
};